home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / UUCICO / dcp.c < prev    next >
C/C++ Source or Header  |  1993-10-03  |  26KB  |  767 lines

  1. /*--------------------------------------------------------------------*/
  2. /*          d c p . c                                                 */
  3. /*                                                                    */
  4. /*          Main routines for UUCICO                                  */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989-1993 by Kendra Electronic            */
  9. /*    Wonderworks.                                                    */
  10. /*                                                                    */
  11. /*    All rights reserved except those explicitly granted by the      */
  12. /*    UUPC/extended license agreement.                                */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*    Copyright (c) Richard H. Lamb 1985, 1986, 1987                  */
  17. /*    Changes Copyright (c) Stuart Lynne 1987                         */
  18. /*--------------------------------------------------------------------*/
  19.  
  20. /*
  21.  *    $Id: dcp.c 1.20 1993/10/03 20:37:34 ahd Exp $
  22.  *
  23.  *    $Log: dcp.c $
  24.  * Revision 1.20  1993/10/03  20:37:34  ahd
  25.  * Don't attempt to suspend port if using network protocol suite
  26.  *
  27.  * Revision 1.19  1993/09/30  03:06:28  ahd
  28.  * Move suspend signal handler into suspend2
  29.  *
  30.  * Revision 1.18  1993/09/29  13:18:06  ahd
  31.  * Don't call suspend handler under DOS Turbo C++ (not impletemented, anyway)
  32.  *
  33.  * Revision 1.17  1993/09/29  04:52:03  ahd
  34.  * Suspend port by port name, not modem file name
  35.  *
  36.  * Revision 1.16  1993/09/27  00:48:43  ahd
  37.  * Control UUCICO in passive mode by K. Rommel
  38.  *
  39.  * Revision 1.15  1993/09/20  04:46:34  ahd
  40.  * OS/2 2.x support (BC++ 1.0 support)
  41.  * TCP/IP support from Dave Watt
  42.  * 't' protocol support
  43.  *
  44.  * Revision 1.14  1993/08/02  03:24:59  ahd
  45.  * Further changes in support of Robert Denny's Windows 3.x support
  46.  *
  47.  * Revision 1.13  1993/07/31  16:26:01  ahd
  48.  * Changes in support of Robert Denny's Windows support
  49.  *
  50.  * Revision 1.12  1993/07/22  23:22:27  ahd
  51.  * First pass at changes for Robert Denny's Windows 3.1 support
  52.  *
  53.  * Revision 1.11  1993/05/30  00:01:47  ahd
  54.  * Allow tracing connection via UUCICO -t flag
  55.  *
  56.  * Revision 1.10  1993/04/11  00:35:46  ahd
  57.  * Global edits for year, TEXT, etc.
  58.  *
  59.  * Revision 1.9  1993/04/05  04:32:19  ahd
  60.  * Allow unique send and receive packet sizes
  61.  *
  62.  * Revision 1.8  1993/01/23  19:08:09  ahd
  63.  * Don't update host status at sysend() if hostp is not initialized
  64.  *
  65.  * Revision 1.7  1992/12/18  12:05:57  ahd
  66.  * Suppress duplicate machine state messages to improve OS/2 scrolling
  67.  *
  68.  * Revision 1.6  1992/12/01  04:37:03  ahd
  69.  * Add standard comment block for header
  70.  *
  71.  * Revision 1.5  1992/11/28  19:51:16  ahd
  72.  * If in multitask mode, only open syslog on demand basis
  73.  *
  74.  * Revision 1.4  1992/11/22  21:30:55  ahd
  75.  * Do not bother to strdup() string arguments
  76.  *
  77.  * 25Aug87 - Added a version number - Jal
  78.  * 25Aug87 - Return 0 if contact made with host, or 5 otherwise.
  79.  * 04Sep87 - Bug causing premature sysend() fixed. - Randall Jessup
  80.  * 13May89 - Add date to version message  - Drew Derbyshire
  81.  * 17May89 - Add '-u' (until) option for login processing
  82.  * 01 Oct 89      Add missing function prototypes
  83.  * 28 Nov 89      Add parse of incoming user id for From record
  84.  * 18 Mar 90      Change checktime() calls to Microsoft C 5.1
  85.  */
  86.  
  87. /*--------------------------------------------------------------------*/
  88. /* This program implements a uucico type file transfer and remote     */
  89. /* execution protocol.                                                */
  90. /*                                                                    */
  91. /* Usage:   UUCICO [-s sys]                                           */
  92. /*                 [-r 0|1]                                           */
  93. /*                 [-x debug]                                         */
  94. /*                 [-d hhmm]                                          */
  95. /*                 [-m modem]                                         */
  96. /*                 [-l logfile]                                       */
  97. /*                 [-x debuglevel]                                    */
  98. /*                 [-w userid]                                        */
  99. /*                 [-z bps]                                           */
  100. /*                 [-t]                                               */
  101. /*                                                                    */
  102. /* e.g.                                                               */
  103. /*                                                                    */
  104. /* UUCICO [-x n] -r 0 [-d hhmm]    client mode, wait for an incoming  */
  105. /*                                 call for 'hhmm'.                   */
  106. /* UUCICO [-x n] -s HOST     call the host "HOST".                    */
  107. /* UUCICO [-x n] -s all      call all known hosts in the systems      */
  108. /*                           file.                                    */
  109. /* UUCICO [-x n] -s any      call any host we have work queued for.   */
  110. /* UUCICO [-x n]             same as the above.                       */
  111. /*--------------------------------------------------------------------*/
  112.  
  113. /*--------------------------------------------------------------------*/
  114. /*                        System include files                        */
  115. /*--------------------------------------------------------------------*/
  116.  
  117. #include <stdio.h>
  118. #include <stdlib.h>
  119. #include <string.h>
  120. #include <sys/types.h>
  121. #include <limits.h>
  122. #include <time.h>
  123.  
  124. #ifdef _Windows
  125. #include <Windows.h>
  126. #endif
  127.  
  128. /*--------------------------------------------------------------------*/
  129. /*                      UUPC/extended prototypes                      */
  130. /*--------------------------------------------------------------------*/
  131.  
  132. #include "lib.h"
  133. #include "arpadate.h"
  134. #include "catcher.h"
  135. #include "checktim.h"
  136. #include "dcp.h"
  137. #include "dcplib.h"
  138. #include "dcpstats.h"
  139. #include "dcpsys.h"
  140. #include "dcpxfer.h"
  141. #include "expath.h"
  142. #include "getopt.h"
  143. #include "hlib.h"
  144. #include "hostable.h"
  145. #include "hostatus.h"
  146. #include "lock.h"
  147. #include "logger.h"
  148. #include "modem.h"
  149. #include "security.h"
  150. #include "ssleep.h"
  151. #include "suspend.h"
  152. #include "commlib.h"
  153.  
  154. #if defined(_Windows)
  155. #include "winutil.h"
  156. #endif
  157.  
  158.  
  159. /*--------------------------------------------------------------------*/
  160. /*    Define passive and active polling modes; passive is             */
  161. /*    sometimes refered to as "slave", "active" as master.  Since     */
  162. /*    the roles can actually switch during processing, we avoid       */
  163. /*    the terms here                                                  */
  164. /*--------------------------------------------------------------------*/
  165.  
  166. typedef enum {
  167.       POLL_PASSIVE = 0,       /* We answer the telephone          */
  168.       POLL_ACTIVE  = 1        /* We call out to another host      */
  169.       } POLL_MODE ;
  170.  
  171. /*--------------------------------------------------------------------*/
  172. /*                          Global variables                          */
  173. /*--------------------------------------------------------------------*/
  174.  
  175. size_t s_pktsize;             /* send packet size for protocol       */
  176. size_t r_pktsize;             /* receive packet size for protocol    */
  177.  
  178. FILE *xfer_stream = NULL;        /* stream for file being handled    */
  179. boolean callnow = FALSE;           /* TRUE = ignore time in L.SYS        */
  180. FILE *fwork = NULL, *fsys= NULL ;
  181. FILE *syslog = NULL;
  182. char workfile[FILENAME_MAX];  /* name of current workfile         */
  183. char *Rmtname = nil(char);    /* system we want to call           */
  184. char rmtname[20];             /* system we end up talking to      */
  185. struct HostTable *hostp;
  186. struct HostStats remote_stats; /* host status, as defined by hostatus */
  187.  
  188. static boolean dialed = FALSE;/* True = We attempted a phone call */
  189.  
  190. currentfile();
  191.  
  192. /*--------------------------------------------------------------------*/
  193. /*                     Local function prototypes                      */
  194. /*--------------------------------------------------------------------*/
  195.  
  196. static CONN_STATE process( const POLL_MODE poll_mode, const char callgrade );
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*    d c p m a i n                                                   */
  200. /*                                                                    */
  201. /*    main program for DCP, called by uuhost                          */
  202. /*--------------------------------------------------------------------*/
  203.  
  204. int dcpmain(int argc, char *argv[])
  205. {
  206.  
  207.    char *logfile_name = NULL;
  208.    boolean  Contacted = FALSE;
  209.  
  210.    int option;
  211.    int poll_mode = POLL_ACTIVE;   /* Default = dial out to system     */
  212.    time_t exit_time = LONG_MAX;
  213.  
  214.    char recvgrade = ALL_GRADES;
  215.    boolean override_grade = FALSE;
  216.    char sendgrade = ALL_GRADES;
  217.  
  218.    char *hotuser = NULL;
  219.    BPS  hotbaud = 0;
  220.  
  221.    fwork = nil(FILE);
  222.  
  223. /*--------------------------------------------------------------------*/
  224. /*                        Process our options                         */
  225. /*--------------------------------------------------------------------*/
  226.  
  227.    while ((option = getopt(argc, argv, "d:g:m:l:r:s:tw:x:z:n?")) != EOF)
  228.       switch (option)
  229.       {
  230.  
  231.       case 'd':
  232.          exit_time = atoi( optarg );
  233.          exit_time = time(NULL) + hhmm2sec(exit_time);
  234.          poll_mode = 0;          // Implies passive polling
  235.          break;
  236.  
  237.       case 'g':
  238.          if (strlen(optarg) == 1 )
  239.             recvgrade = *optarg;
  240.          else {
  241.             recvgrade = checktime( optarg );
  242.                                  /* Get restriction for this hour */
  243.             if ( ! recvgrade )   /* If no class, use the default  */
  244.                recvgrade = ALL_GRADES;
  245.          }
  246.          override_grade = TRUE;
  247.          break;
  248.  
  249.       case 'm':                     /* Override in modem name     */
  250.          E_inmodem = optarg;
  251.          poll_mode = 0;             /* Presume passive polling */
  252.          break;
  253.  
  254.       case 'l':                     /* Log file name              */
  255.          logfile_name = optarg;
  256.          break;
  257.  
  258.       case 'n':
  259.          callnow = TRUE;
  260.          break;
  261.  
  262.       case 'r':
  263.          poll_mode = atoi(optarg);
  264.          break;
  265.  
  266.       case 's':
  267.          Rmtname = optarg;
  268.          break;
  269.  
  270.       case 't':
  271.          traceEnabled = TRUE;
  272.          break;
  273.  
  274.       case 'x':
  275.          debuglevel = atoi(optarg);
  276.          break;
  277.  
  278.       case 'z':
  279.          hotbaud = atoi(optarg);
  280.          break;
  281.  
  282.       case 'w':
  283.          poll_mode = 0;       /* Presume passive polling */
  284.          hotuser = optarg;
  285.          break;
  286.  
  287.       case '?':
  288.          puts("\nUsage:\tuucico\t"
  289.          "[-s [all | any | sys]] [-r 1|0] [-x debug] [-d hhmm]\n"
  290.          "\t\t[-n] [-t] [-w user] [-l logfile] [-m modem] [-z bps]");
  291.          return 4;
  292.       }
  293.  
  294. /*--------------------------------------------------------------------*/
  295. /*                Abort if any options were left over                 */
  296. /*--------------------------------------------------------------------*/
  297.  
  298.    if (optind != argc) {
  299.       puts("Extra parameter(s) at end.");
  300.       return 4;
  301.    }
  302.  
  303.    if (Rmtname == nil(char))
  304.       Rmtname = "any";
  305.  
  306. /*--------------------------------------------------------------------*/
  307. /*        Initialize logging and the name of the systems file         */
  308. /*--------------------------------------------------------------------*/
  309.  
  310.    openlog( logfile_name );
  311.  
  312.    if (bflag[F_SYSLOG] && ! bflag[F_MULTITASK])
  313.    {
  314.       syslog = FOPEN(SYSLOG, "a",TEXT_MODE);
  315.       if ((syslog == nil(FILE)) || setvbuf( syslog, NULL, _IONBF, 0))
  316.       {
  317.          printerr( SYSLOG );
  318.          panic();
  319.       }
  320.    }
  321.  
  322.    if ( terminate_processing )
  323.       return 100;
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*                        Initialize security                         */
  327. /*--------------------------------------------------------------------*/
  328.  
  329.    if ( !LoadSecurity())
  330.    {
  331.       printmsg(0,"Unable to initialize security, see previous message");
  332.       panic();
  333.    }
  334.  
  335.    if ( terminate_processing )
  336.       return 100;
  337.  
  338. #if defined(_Windows)
  339.    atexit(CloseEasyWin);       // Auto-close EasyWin window on exit
  340. #endif
  341.  
  342.    atexit( shutDown );        /* Insure port is closed by panic()    */
  343.    remote_stats.save_hstatus = nocall;
  344.                               /* Known state for automatic status
  345.                                  update                              */
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*                     Begin main processing loop                     */
  349. /*--------------------------------------------------------------------*/
  350.  
  351.    if (poll_mode == POLL_ACTIVE) {
  352.  
  353.       CONN_STATE m_state = CONN_INITSTAT;
  354.       CONN_STATE old_state = CONN_EXIT;
  355.  
  356.       printmsg(2, "calling \"%s\", debug=%d", Rmtname, debuglevel);
  357.  
  358.       if ((fsys = FOPEN(E_systems, "r",TEXT_MODE)) == nil(FILE))
  359.       {
  360.          printerr(E_systems);
  361.          panic();
  362.       }
  363.  
  364.       setvbuf( fsys, NULL, _IONBF, 0);
  365.  
  366.       while (m_state != CONN_EXIT )
  367.       {
  368.          printmsg(old_state == m_state ? 10 : 4 ,
  369.                   "M state = %c", m_state);
  370.          old_state = m_state;
  371.  
  372.          if (bflag[F_MULTITASK] &&
  373.               (hostp != NULL ) &&
  374.               (remote_stats.save_hstatus != hostp->hstatus ))
  375.          {
  376.             dcupdate();
  377.             remote_stats.save_hstatus = hostp->hstatus;
  378.          }
  379.  
  380.          switch (m_state)
  381.          {
  382.             case CONN_INITSTAT:
  383.                HostStatus();
  384.                m_state = CONN_INITIALIZE;
  385.                break;
  386.  
  387.             case CONN_INITIALIZE:
  388.                hostp = NULL;
  389.  
  390.                if ( locked )
  391.                   UnlockSystem();
  392.  
  393.                m_state = getsystem(recvgrade);
  394.                if ( hostp != NULL )
  395.                   remote_stats.save_hstatus = hostp->hstatus;
  396.                break;
  397.  
  398.             case CONN_CHECKTIME:
  399.                sendgrade = checktime(flds[FLD_CCTIME]);
  400.  
  401.                if ( (override_grade && sendgrade) || callnow )
  402.                   sendgrade = recvgrade;
  403.  
  404.                if ( !CallWindow( sendgrade ))
  405.                   m_state = CONN_INITIALIZE;
  406.                else if ( LockSystem( hostp->hostname , B_UUCICO))
  407.                {
  408.                   dialed = TRUE;
  409.                   time(&hostp->hstats->ltime);
  410.                                  /* Save time of last attempt to call   */
  411.                   hostp->hstatus = autodial;
  412.                   m_state = CONN_MODEM;
  413.                }
  414.                else
  415.                   m_state = CONN_INITIALIZE;
  416.  
  417.                break;
  418.  
  419.             case CONN_MODEM:
  420.                if (getmodem(flds[FLD_TYPE]))
  421.                   m_state = CONN_DIALOUT;
  422.                else {
  423.                   hostp->hstatus = invalid_device;
  424.                   m_state = CONN_INITIALIZE;
  425.                }
  426.                break;
  427.  
  428.             case CONN_DIALOUT:
  429.  
  430.                if ( !IsNetwork() && suspend_other(TRUE, M_device ) < 0 )
  431.                {
  432.                   hostp->hstatus =  nodevice;
  433.                   m_state = CONN_INITIALIZE;    // Try next system
  434.                }
  435.                else
  436.                   m_state = callup( );
  437.                break;
  438.  
  439.             case CONN_PROTOCOL:
  440.                m_state = startup_server( (char)
  441.                                           (bflag[F_SYMMETRICGRADES] ?
  442.                                           sendgrade  : recvgrade) );
  443.                break;
  444.  
  445.             case CONN_SERVER:
  446.                m_state = process( poll_mode, recvgrade );
  447.                Contacted = TRUE;
  448.                break;
  449.  
  450.             case CONN_TERMINATE:
  451.                m_state = sysend();
  452.                if ( hostp != NULL )
  453.                {
  454.                   if (hostp->hstatus == inprogress)
  455.                      hostp->hstatus = call_failed;
  456.                   dcstats();
  457.                }
  458.                break;
  459.  
  460.             case CONN_DROPLINE:
  461.                shutDown();
  462.                UnlockSystem();
  463.                suspend_other(FALSE, M_device);
  464.                m_state = CONN_INITIALIZE;
  465.                break;
  466.  
  467.             case CONN_EXIT:
  468.                break;
  469.  
  470.             default:
  471.                printmsg(0,"dcpmain: Unknown master state = %c",m_state );
  472.                panic();
  473.                break;
  474.          } /* switch */
  475.  
  476.          if ( terminate_processing )
  477.             m_state = CONN_EXIT;
  478.  
  479.       } /* while */
  480.  
  481.       fclose(fsys);
  482.  
  483.    }
  484.    else { /* client mode */
  485.  
  486.       CONN_STATE s_state = CONN_INITIALIZE;
  487.       CONN_STATE old_state = CONN_EXIT;
  488.  
  489.       if (!getmodem(E_inmodem))  /* Initialize modem configuration      */
  490.          panic();                /* Avoid loop if bad modem name        */
  491.  
  492.       if ( ! IsNetwork() )
  493.          suspend_init(M_device);
  494.  
  495.       while (s_state != CONN_EXIT )
  496.       {
  497.          printmsg(s_state == old_state ? 10 : 4 ,
  498.                   "S state = %c", s_state);
  499.          old_state = s_state;
  500.  
  501.          if (bflag[F_MULTITASK] &&
  502.               (hostp != NULL ) &&
  503.               (remote_stats.save_hstatus != hostp->hstatus ))
  504.          {
  505.             printmsg(2, "Updating status for host %s, status %d",
  506.                         hostp->hostname ,
  507.                         (int) hostp->hstatus );
  508.             dcupdate();
  509.             remote_stats.save_hstatus = hostp->hstatus;
  510.          }
  511.  
  512.          switch (s_state) {
  513.             case CONN_INITIALIZE:
  514.                if ( hotuser == NULL )
  515.                   s_state = CONN_ANSWER;
  516.                else
  517.                   s_state = CONN_HOTMODEM;
  518.                break;
  519.  
  520.             case CONN_WAIT:
  521. #if !defined(__TURBOC__) || defined(BIT32ENV)
  522.               s_state = suspend_wait();
  523. #else
  524.               panic();                 // Why are we here?!
  525. #endif
  526.               break;
  527.  
  528.             case CONN_ANSWER:
  529.                s_state = callin( exit_time );
  530.                break;
  531.  
  532.             case CONN_HOTMODEM:
  533.                s_state = callhot( hotbaud );
  534.                break;
  535.  
  536.             case CONN_HOTLOGIN:
  537.                if ( loginbypass( hotuser ) )
  538.                   s_state = CONN_INITSTAT;
  539.                else
  540.                   s_state = CONN_DROPLINE;
  541.                break;
  542.  
  543.             case CONN_LOGIN:
  544.                if ( login( ) )
  545.                   s_state = CONN_INITSTAT;
  546.                else
  547.                   s_state = CONN_DROPLINE;
  548.                break;
  549.  
  550.             case CONN_INITSTAT:
  551.                HostStatus();
  552.                s_state = CONN_PROTOCOL;
  553.                break;
  554.  
  555.             case CONN_PROTOCOL:
  556.                s_state = startup_client(&sendgrade);
  557.                break;
  558.  
  559.             case CONN_CLIENT:
  560.                Contacted = TRUE;
  561.                s_state = process( poll_mode, sendgrade );
  562.                break;
  563.  
  564.             case CONN_TERMINATE:
  565.                s_state = sysend();
  566.                if ( hostp != NULL )
  567.                   dcstats();
  568.                break;
  569.  
  570.             case CONN_DROPLINE:
  571.                shutDown();
  572.                if ( locked )     /* Cause could get here w/o
  573.                                     locking                    */
  574.                   UnlockSystem();
  575.                s_state = CONN_EXIT;
  576.                break;
  577.  
  578.             case CONN_EXIT:
  579.                break;
  580.  
  581.             default:
  582.                printmsg(0,"dcpmain: Unknown slave state = %c",s_state );
  583.                panic();
  584.                break;
  585.          } /* switch */
  586.  
  587.          if ( terminate_processing )
  588.             s_state = CONN_EXIT;
  589.  
  590.       } /* while */
  591.    } /* else */
  592.  
  593. /*--------------------------------------------------------------------*/
  594. /*                         Report our results                         */
  595. /*--------------------------------------------------------------------*/
  596.  
  597.    if (!Contacted && (poll_mode == POLL_ACTIVE))
  598.    {
  599.       if (dialed)
  600.          printmsg(0, "Could not connect to remote system.");
  601.       else
  602.          printmsg(0,
  603.                "No work for requested system or wrong time to call.");
  604.    }
  605.  
  606.    dcupdate();
  607.  
  608.    if (bflag[F_SYSLOG] && ! bflag[F_MULTITASK])
  609.       fclose(syslog);
  610.  
  611.    return terminate_processing ? 100 : (Contacted ? 0 : 5);
  612.  
  613. } /*dcpmain*/
  614.  
  615.  
  616. /*--------------------------------------------------------------------*/
  617. /*    p r o c e s s                                                   */
  618. /*                                                                    */
  619. /*    The procotol state machine                                      */
  620. /*--------------------------------------------------------------------*/
  621.  
  622. static CONN_STATE process( const POLL_MODE poll_mode, const char callgrade )
  623. {
  624.    boolean master  = ( poll_mode == POLL_ACTIVE );
  625.    boolean aborted = FALSE;
  626.    XFER_STATE state =  master ? XFER_SENDINIT : XFER_RECVINIT;
  627.    XFER_STATE old_state = XFER_EXIT;
  628.                               /* Initialized to any state but the
  629.                                  original value of "state"           */
  630.    XFER_STATE save_state = XFER_EXIT;
  631.  
  632. /*--------------------------------------------------------------------*/
  633. /*  Yea old state machine for the high level file transfer procotol   */
  634. /*--------------------------------------------------------------------*/
  635.  
  636.    while( state != XFER_EXIT )
  637.    {
  638.       printmsg(state == old_state ? 14 : 4 ,
  639.                "process: Machine state is = %c", state );
  640.       old_state = state;
  641.  
  642.       if ( terminate_processing != aborted )
  643.       {
  644.          aborted = terminate_processing;
  645.          state = XFER_ABORT;
  646.       }
  647.  
  648.       switch( state )
  649.       {
  650.  
  651.          case XFER_SENDINIT:  /* Initialize outgoing protocol        */
  652.             state = sinit();
  653.             break;
  654.  
  655.          case XFER_RECVINIT:  /* Initialize Receive protocol         */
  656.             state = rinit();
  657.             break;
  658.  
  659.          case XFER_MASTER:    /* Begin master mode                   */
  660.             master = TRUE;
  661.             state = XFER_NEXTJOB;
  662.             break;
  663.  
  664.          case XFER_SLAVE:     /* Begin slave mode                    */
  665.             master = FALSE;
  666.             state = XFER_RECVHDR;
  667.             break;
  668.  
  669.          case XFER_NEXTJOB:   /* Look for work in local queue        */
  670.             state = scandir( rmtname, callgrade );
  671.             break;
  672.  
  673.          case XFER_REQUEST:   /* Process next file in current job
  674.                                  in queue                            */
  675.             state = newrequest();
  676.             break;
  677.  
  678.          case XFER_PUTFILE:   /* Got local tranmit request           */
  679.             state = ssfile();
  680.             break;
  681.  
  682.          case XFER_GETFILE:   /* Got local tranmit request           */
  683.             state = srfile();
  684.             break;
  685.  
  686.          case XFER_SENDDATA:  /* Remote accepted our work, send data */
  687.             state = sdata();
  688.             break;
  689.  
  690.          case XFER_SENDEOF:   /* File xfer complete, send EOF        */
  691.             state = seof( master );
  692.             break;
  693.  
  694.          case XFER_FILEDONE:  /* Receive or transmit is complete     */
  695.             state = master ? XFER_REQUEST : XFER_RECVHDR;
  696.             break;
  697.  
  698.          case XFER_NOLOCAL:   /* No local work, remote have any?     */
  699.             state = sbreak();
  700.             break;
  701.  
  702.          case XFER_NOREMOTE:  /* No remote work, local have any?     */
  703.             state = schkdir( poll_mode == POLL_ACTIVE, callgrade );
  704.             break;
  705.  
  706.          case XFER_RECVHDR:   /* Receive header from other host      */
  707.             state = rheader();
  708.             break;
  709.  
  710.          case XFER_TAKEFILE:  /* Set up to receive remote requested
  711.                                  file transfer                       */
  712.             state = rrfile();
  713.             break;
  714.  
  715.          case XFER_GIVEFILE:  /* Set up to transmit remote
  716.                                  requuest file transfer              */
  717.             state = rsfile();
  718.             break;
  719.  
  720.          case XFER_RECVDATA:  /* Receive file data from other host   */
  721.             state = rdata();
  722.             break;
  723.  
  724.          case XFER_RECVEOF:
  725.             state = reof();
  726.             break;
  727.  
  728.          case XFER_LOST:      /* Lost the other host, flame out      */
  729.             printmsg(0,"process: Connection lost to %s, "
  730.                        "previous system state = %c",
  731.                        rmtname, save_state );
  732.             hostp->hstatus = call_failed;
  733.             state = XFER_EXIT;
  734.             break;
  735.  
  736.          case XFER_ABORT:     /* Internal error, flame out           */
  737.             printmsg(0,"process: Aborting connection to %s, "
  738.                        "previous system state = %c",
  739.                        rmtname, save_state );
  740.             hostp->hstatus = call_failed;
  741.             state = XFER_ENDP;
  742.             break;
  743.  
  744.          case XFER_ENDP:      /* Terminate the protocol              */
  745.             state = endp();
  746.             break;
  747.  
  748.          default:
  749.             printmsg(0,"process: Unknown state = %c, "
  750.                        "previous system state = %c",
  751.                        state, save_state );
  752.             state = XFER_ABORT;
  753.             break;
  754.       } /* switch */
  755.  
  756.       save_state = old_state; /* Used only if we abort               */
  757.  
  758.    } /* while( state != XFER_EXIT ) */
  759.  
  760. /*--------------------------------------------------------------------*/
  761. /*           Protocol is complete, terminate the connection           */
  762. /*--------------------------------------------------------------------*/
  763.  
  764.    return CONN_TERMINATE;
  765.  
  766. } /* process */
  767.